#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "abrir.h"
#include "tiempo.h"
#include <QDebug>
#include <QProcess>
#include <sys/shm.h>
#include <unistd.h>
#include <signal.h>
#include <QAbstractItemModel>

extern "C"{
    #include "archivos.h"
}
/*-------- Estructuras de datos ---------*/

typedef struct{
    int pid;
    int li,lf;
    float resultado;
    char listo; //Indica si el proceso termino o no
}Proceso;

typedef struct{
    float resultado1;
    float resultado2;
    char tieneResultado2; //Indica si tiene resultado 2
    char listo; //Indica si el resultado esta listo o no
}Resultado;


QString nombre_arch;
QProcess *proc;
int *procPid;
int id_memoria;
int id_memoria2;
int *lineas;
int *nro_procesos;
int *tiempoRetraso;
int operacionesListas=0;
int *relacionListos;
Operacion *operaciones;
Resultado *resultados;
Proceso *procesos;
QTimer *timer;
char flagNoIniciado=0;


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    Statlabel = new QLabel(this);
    Statprogress = new QProgressBar(this);

    ui->statusBar->addPermanentWidget(Statlabel);
    ui->statusBar->addPermanentWidget(Statprogress);    
    Statprogress->setTextVisible(true);
    Statprogress->setValue(0);

    proc = new QProcess( this );
    //proc->setProcessChannelMode(QProcess::ForwardedChannels);
    connect(proc,SIGNAL(readyReadStandardOutput()),this,SLOT(readyReadStandardOutput()));
    connect(proc,SIGNAL(readyReadStandardError()),this,SLOT(readyReadStandardError()));

    timer = new QTimer(this);
    timer->setInterval(1000);
    connect(timer,SIGNAL(timeout()),this,SLOT(updateResults()));
}

MainWindow::~MainWindow()
{
    int pidaux;

    /*if(procPid!=NULL){
        kill(*procPid,SIGCONT);
    }
    shmdt (lineas);
    shmctl (id_memoria, IPC_RMID, (struct shmid_ds *)NULL);
    shmdt (resultados);*/
    if(flagNoIniciado==1){
        kill(*procPid,SIGCONT);
        pidaux=*procPid;
    }
    if(ui->actionFinalizar->isEnabled()){
        this->on_actionFinalizar_triggered();

    }
    if(flagNoIniciado==1){
        kill(pidaux,SIGKILL);
    }
    delete ui;
}

void MainWindow::on_actionAbrir_triggered()
{
    Abrir abrir;

    abrir.setModal(true);
    abrir.exec();
    if(!abrir.getDir().isEmpty()){
        flagNoIniciado=1;
        nombre_arch = abrir.getDir();

        ui->statusBar->showMessage("Archivo cargado:"+nombre_arch,5000);
        ui->actionCerrar_archivo->setEnabled(true);
        ui->actionIniciar->setEnabled(true);
        ui->actionFinalizar->setEnabled(true);
        ui->actionTiempo->setEnabled(true);
        //qDebug() << nombre_arch;

        //Memoria compartida para nro de lineas y nro de procesos
        key_t clave = ftok("/bin/ls",3151);
        if(clave==-1){
            qDebug() << "No se obtuvo la clave para SHM";
            this->~MainWindow();
        }
        id_memoria = shmget (clave, sizeof(int)*4, 0666 | IPC_CREAT);
        if(id_memoria==-1){
            qDebug() << "No se obtuvo un id para SHM";
            this->~MainWindow();
        }
        lineas = (int *)shmat (id_memoria, NULL,SHM_RND);
        nro_procesos = lineas+sizeof(int);
        procPid = lineas+sizeof(int)*2;
        tiempoRetraso=lineas+sizeof(int)*3;

        //Creacion del proceso logico
        bool ok = proc->startDetached("./logicProcess", QStringList() << nombre_arch);

        if (ok){
            qDebug() << "Entro";
        }else{
            qDebug() << "No entro";
        }
    }
}

void MainWindow::updateResults(){
    int i;
    char flag=0;

    //qDebug() << operacionesListas << (*lineas) << ((operacionesListas*100)/(*lineas));

    if(operacionesListas<(*lineas)){
        for(i=0;i<(*lineas);i++){
            if(resultados[i].listo!=relacionListos[i]){
                relacionListos[i]=resultados[i].listo;
                operacionesListas++;
                flag=1;
            }
        }
        if(flag==1){

            Statprogress->setValue((operacionesListas*100)/(*lineas));
            /*if(ui->treeWidget->currentItem()!=NULL){
                this->on_treeWidget_itemClicked(ui->treeWidget->currentItem(),0);
            }*/
        }
        qDebug() << "Timer";
    }else{
        timer->stop();
        Statprogress->setValue(100);
        Statlabel->setText("Listo");
        /*if(ui->treeWidget->currentItem()!=NULL){
            this->on_treeWidget_itemClicked(ui->treeWidget->currentItem(),0);
        }*/
    }


}

void MainWindow::on_actionIniciar_triggered()
{
    flagNoIniciado=0;
    ui->actionFinalizar->setEnabled(true);
    ui->actionPausa->setEnabled(true);
    ui->actionTiempo->setEnabled(false);
    ui->actionIniciar->setEnabled(false);

    Statlabel->setText("Procesando");

    operaciones=(Operacion*)malloc(sizeof(Operacion)*(*lineas));
    relacionListos=(int*)malloc(sizeof(int)*(*lineas));
    leer_archivo((char*)nombre_arch.toStdString().c_str(),(*lineas),operaciones);

    //Memoria compartida desde logicProcess
    key_t clave2 = ftok("/bin/ls",3152);
    if(clave2==-1){
        qDebug() << "No se obtuvo la clave para SHM2 GUI\n";
        exit(0);
    }
    id_memoria2 = shmget (clave2,sizeof(Resultado)*(*lineas)+sizeof(Proceso)*(*nro_procesos),0666);
    if(id_memoria2==-1){
        qDebug() << "No se obtuvo un id para SHM2 GUI\n";
        exit(0);
    }
    resultados=(Resultado *)shmat(id_memoria2,NULL,SHM_RND);
    procesos=(Proceso*)resultados+sizeof(Resultado)*(*lineas);
    //operaciones=(Operacion*)procesos+sizeof(Operacion)*(*lineas);

    addRoot("Principal",QString::number(*procPid));

    int i;
    for(i=0;i<*nro_procesos;i++){
        addChild(ui->treeWidget->topLevelItem(0),i,procesos[i].pid,procesos[i].li,procesos[i].lf);
    }

    kill(*procPid,SIGCONT);


    //timer->start();
}

void MainWindow::readyReadStandardOutput(){
    qDebug()<< proc->readAllStandardOutput();
}

void MainWindow::readyReadStandardError(){
    qDebug() << proc->readAllStandardError();
}

void MainWindow::on_actionSalir_triggered()
{
    close();
}

void MainWindow::on_actionCerrar_archivo_triggered()
{
    nombre_arch="";
    ui->actionCerrar_archivo->setEnabled(false);
    this->on_actionFinalizar_triggered();
}



void MainWindow::on_actionFinalizar_triggered()
{
    flagNoIniciado=0;
    //ui->actionIniciar->setEnabled(true);
    ui->actionPausa->setEnabled(false);
    ui->actionFinalizar->setEnabled(false);
    //ui->actionTiempo->setEnabled(true);
    ui->actionContinuar->setEnabled(false);
    ui->actionCerrar_archivo->setEnabled(false);

    ui->tableWidget->clearContents();
    ui->treeWidget->clear();

    timer->stop();

    if(procPid!=NULL){
        kill(*procPid,SIGCONT);
    }
    shmdt (lineas);
    shmctl (id_memoria, IPC_RMID, (struct shmid_ds *)NULL);
    shmdt (resultados);

    ui->tableWidget->setColumnCount(0);

}

void MainWindow::on_actionPausa_triggered()
{
    int j;

    ui->actionContinuar->setEnabled(true);
    ui->actionPausa->setEnabled(false);

    kill(*procPid,SIGSTOP);
    for(j=0;j<(*nro_procesos);j++){
        kill(procesos[j].pid,SIGSTOP);
    }

    timer->stop();
}

void MainWindow::on_actionContinuar_triggered()
{
    int j;

    ui->actionPausa->setEnabled(true);
    ui->actionContinuar->setEnabled(false);

    kill(*procPid,SIGCONT);
    for(j=0;j<(*nro_procesos);j++){
        kill(procesos[j].pid,SIGCONT);
    }

    timer->start();
}

void MainWindow::on_actionTiempo_triggered()
{
    Tiempo ventanaTiempo;

    ventanaTiempo.setModal(true);
    ventanaTiempo.exec();
    if(ventanaTiempo.Accepted){
        *tiempoRetraso=ventanaTiempo.getTiempo();
    }
}

void MainWindow::addRoot(QString name,QString pid){
    QTreeWidgetItem *item = new QTreeWidgetItem(ui->treeWidget);
    item->setText(0,name);
    item->setText(1,pid);
    ui->treeWidget->addTopLevelItem(item);
}

void MainWindow::addChild(QTreeWidgetItem *parent,int name,int pid,int li,int lf){
    QTreeWidgetItem *item = new QTreeWidgetItem();
    item->setText(0,QString::number(name));
    item->setText(1,QString::number(pid));
    item->setText(2,QString::number(li));
    item->setText(3,QString::number(lf));
    parent->addChild(item);
}




void MainWindow::on_treeWidget_itemClicked(QTreeWidgetItem *item, int column)
{
    int i, li,lf,j;

    li=item->text(2).toInt();
    lf=item->text(3).toInt();
    if(li==0 && lf==0){
        lf=(*lineas)-1;
    }
    ui->tableWidget->setRowCount(lf-li+1);
    ui->tableWidget->setColumnCount(4);

    for(i=li,j=0;i<=lf;i++,j++){
        ui->tableWidget->setItem(j,0,new QTableWidgetItem(QString::number(i)));
        ui->tableWidget->setItem(j,1,new QTableWidgetItem(operaciones[i].operacion));
        if(resultados[i].listo){
            ui->tableWidget->setItem(j,2,new QTableWidgetItem(QString::number(resultados[i].resultado1)));
            if(resultados[i].tieneResultado2)
                ui->tableWidget->setItem(j,3,new QTableWidgetItem(QString::number(resultados[i].resultado2)));
        }
    }
    ui->tableWidget->resizeColumnsToContents();
}
